import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JTextField;

public class Koder extends JFrame {

    public static int broj_celija;
    public static int visina_frejma;
    public static int sirina_frejma;
    static String vektor1 = "";
    static String vektor2 = "";
    static String[][] izlaz;
    static String[][] tranzicija;
    private VectorInput inputBox1, inputBox2;
    private DijagramStanja dij_stanja;

    public Koder(int a) {
	broj_celija = a;
	visina_frejma = 600;
	sirina_frejma = 1000;
	dij_stanja = new DijagramStanja();
	super.setTitle("Blok dijagram kodera");
	super.setSize(sirina_frejma, visina_frejma);
	super.setResizable(false);
	super.setVisible(true);
	this.setDefaultCloseOperation(EXIT_ON_CLOSE);
	this.addMouseListener((MouseListener) new Koder.clickListener());
	this.addKeyListener((KeyListener) new Koder.keyListener());
	for (int i = 0; i < broj_celija; i++) {
	    vektor1 = vektor1.concat("0");
	    vektor2 = vektor2.concat("0");
	}
	this.puniTabeluTranzicija();
	this.puniTabeluIzlaza();
    }

    private class keyListener extends KeyAdapter {
	public void keyPressed(KeyEvent event) {
	    if (event.isControlDown()) {
		if (event.getKeyCode() == KeyEvent.VK_LEFT) {
		    if (broj_celija > 1) {
			broj_celija -= 1;
			vektor1 = vektor1.substring(1);
			vektor2 = vektor2.substring(1);
			DijagramStanja.izabrano = false;
			Koder.this.dij_stanja.repaint();
			Koder.this.repaint();

		    }
		}
		if (event.getKeyCode() == KeyEvent.VK_RIGHT) {
		    broj_celija += 1;
		    vektor1 = new String("0").concat(vektor1);
		    vektor2 = new String("0").concat(vektor2);
		    Koder.this.repaint();
		    DijagramStanja.izabrano = false;
		    Koder.this.dij_stanja.repaint();
		}
		if (event.getKeyCode() == KeyEvent.VK_ENTER) {
		    new TrelisDijagram();
		    TrelisDijagram.g = Koder.this;
		    Koder.this.setEnabled(false);
		}
	    }
	}
    }

    private class clickListener extends MouseAdapter {
	public void mouseClicked(MouseEvent event) {
	    int x = Koder.this.getMousePosition().x;
	    int y = Koder.this.getMousePosition().y;
	    if (Point2D.distance(x, y, sirina_frejma / 2, visina_frejma / 2 - visina_frejma / 3 - 15) < 15) {
		if ((Koder.this.inputBox2 == null) || !(Koder.this.inputBox2.isShowing())) {
		    if ((Koder.this.inputBox1 == null) || !(Koder.this.inputBox1.isShowing())) {
			Koder.this.inputBox1 = new VectorInput(1);
		    }
		}
	    }
	    if (Point2D.distance(x, y, sirina_frejma / 2, visina_frejma / 2 + visina_frejma / 3 + 15) < 15) {
		if ((Koder.this.inputBox1 == null) || !(Koder.this.inputBox1.isShowing())) {
		    if ((Koder.this.inputBox2 == null) || !(Koder.this.inputBox2.isShowing())) {
			Koder.this.inputBox2 = new VectorInput(2);
		    }
		}
	    }
	}
    }

    private class VectorInput extends JDialog {
	public JTextField inputField;
	public int ID;

	public VectorInput(int ID) {
	    super(Koder.this, "Vektor " + ID);
	    this.ID = ID;
	    inputField = new JTextField();
	    inputField.setHorizontalAlignment(JTextField.CENTER);
	    inputField.addKeyListener((KeyListener) new Koder.VectorInput.keyListener());
	    this.add(inputField);
	    // this.setModalityType(JDialog.ModalityType.TOOLKIT_MODAL);
	    this.setSize(100, 50);
	    this.setResizable(false);
	    this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
	    if (this.ID == 1) {
		this.setLocation(Koder.this.getLocation().x + sirina_frejma / 2 - this.getWidth() - 50, Koder.this
			.getLocation().y
			+ visina_frejma / 2 - 200 - 40);
	    }
	    if (this.ID == 2) {
		this.setLocation(Koder.this.getLocation().x + sirina_frejma / 2 - this.getWidth() - 50, Koder.this
			.getLocation().y
			+ visina_frejma / 2 + 200 - 10);
	    }
	    this.setVisible(true);
	}

	private class keyListener extends KeyAdapter {
	    Koder.VectorInput active;

	    public void keyPressed(KeyEvent event) {
		char c = event.getKeyChar();
		if ((Koder.this.inputBox2 == null) || !(Koder.this.inputBox2.isShowing())) {
		    active = Koder.this.inputBox1;
		} else {
		    active = Koder.this.inputBox2;
		}
		if (((c == KeyEvent.VK_0) || (c == KeyEvent.VK_1))
			&& (active.inputField.getText().length() < broj_celija)) {
		    if (active.inputField.isEditable() == false) {
			active.inputField.setEditable(true);
		    }
		} else if (c == KeyEvent.VK_BACK_SPACE) {
		    if (active.inputField.isEditable() == false) {
			active.inputField.setEditable(true);
		    }
		} else if ((c == KeyEvent.VK_ENTER) && (active.inputField.getText().length() == broj_celija)) {
		    if (active == Koder.this.inputBox1) {
			vektor1 = active.inputField.getText();
		    }
		    if (active == Koder.this.inputBox2) {
			vektor2 = active.inputField.getText();
		    }
		    active.dispose();
		    Koder.this.repaint();
		    Koder.this.puniTabeluIzlaza();
		} else if (c == KeyEvent.VK_ESCAPE) {
		    active.dispose();
		} else {
		    if (active.inputField.isEditable() == true) {
			active.inputField.setEditable(false);
			active.inputField.setBackground(Color.white);
			active.inputField.requestFocusInWindow();
		    }
		}
	    }
	}
    }

    private void puniTabeluTranzicija() {
	int a = (int) Math.pow(2, broj_celija - 1);
	tranzicija = new String[a][2];
	String s1, s2, s3;
	for (int i = 0; i < a; i++) {
	    s1 = DijagramStanja.toBin(i, broj_celija - 1);
	    s2 = "0";
	    s2 = s2.concat(s1);
	    s2 = s2.substring(0, broj_celija - 1);
	    s3 = "1";
	    s3 = s3.concat(s1);
	    s3 = s3.substring(0, broj_celija - 1);
	    tranzicija[i][0] = s2;
	    tranzicija[i][1] = s3;
	}
    }

    private void puniTabeluIzlaza() {
	int a = (int) Math.pow(2, broj_celija - 1);
	izlaz = new String[a][2];
	for (int i = 0; i < a; i++) {
	    String string1 = odrediIzlazSabiraca(new String("0").concat(DijagramStanja.toBin(i, broj_celija - 1)),
		    Koder.vektor1);
	    String string2 = odrediIzlazSabiraca(new String("0").concat(DijagramStanja.toBin(i, broj_celija - 1)),
		    Koder.vektor2);
	    izlaz[i][0] = string1.concat(string2);
	    string1 = odrediIzlazSabiraca(new String("1").concat(DijagramStanja.toBin(i, broj_celija - 1)),
		    Koder.vektor1);
	    string2 = odrediIzlazSabiraca(new String("1").concat(DijagramStanja.toBin(i, broj_celija - 1)),
		    Koder.vektor2);
	    izlaz[i][1] = string1.concat(string2);
	}
    }

    private String odrediIzlazSabiraca(String s1, String s2) {
	int result = 0;
	if (s1.length() == s2.length()) {
	    for (int i = 0; i < s1.length(); i++) {
		int n1 = Integer.parseInt(s1.substring(i, i + 1), 2);
		int n2 = Integer.parseInt(s2.substring(i, i + 1), 2);
		result = result + (n1 * n2);
	    }
	}
	result = result % 2;
	return Integer.toString(result);
    }

    public void paint(Graphics g) {
	Graphics2D g2 = (Graphics2D) g;
	sirina_frejma = Koder.super.getWidth();
	visina_frejma = Koder.super.getHeight();
	if (isOpaque()) { // paint background
	    GradientPaint gp = new GradientPaint(0, visina_frejma, Color.blue, sirina_frejma, 0, Color.white);
	    g2.setPaint(gp);
	    g.fillRect(0, 0, sirina_frejma, visina_frejma);
	}

	this.puniTabeluTranzicija();
	this.puniTabeluIzlaza();

	Point2D.Double[][] tacke_kvadrata = new Point2D.Double[4][broj_celija];
	for (int i = 0; i < Koder.broj_celija; i++) {
	    Point2D.Double[] a = crtajKvadrat((sirina_frejma / 2 - (35 + 50 * (broj_celija - 1)) + i * 100), g2);
	    for (int j = 0; j < 4; j++) {
		tacke_kvadrata[j][i] = a[j];
	    }
	    if (i > 0) {
		Line2D.Double l1 = new Line2D.Double(tacke_kvadrata[1][i - 1], tacke_kvadrata[0][i]);
		g2.setStroke(new BasicStroke(4));
		g2.setPaint(Color.black);
		g2.draw(l1);
	    }
	    if ((vektor1 != null) && (vektor1.charAt(i) == '1')) {
		Line2D.Double l1 = new Line2D.Double(tacke_kvadrata[2][i], new Point2D.Double(sirina_frejma / 2,
			visina_frejma / 2 - visina_frejma / 3 - 15));
		g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
		g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
			RenderingHints.VALUE_ANTIALIAS_ON));
		g2.setPaint(Color.black);
		g2.draw(l1);
	    }
	    if ((vektor2 != null) && (vektor2.charAt(i) == '1')) {
		Line2D.Double l1 = new Line2D.Double(tacke_kvadrata[3][i], new Point2D.Double(sirina_frejma / 2,
			visina_frejma / 2 + visina_frejma / 3 + 15));
		g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
		g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
			RenderingHints.VALUE_ANTIALIAS_ON));
		g2.setPaint(Color.black);
		g2.draw(l1);
	    }
	}
	g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_FRACTIONALMETRICS,
		RenderingHints.VALUE_FRACTIONALMETRICS_ON));
	crtajSabirac(visina_frejma / 2 - 200 - 30, g2);
	crtajSabirac(visina_frejma / 2 + 200, g2);

	// provodnici od sabiraca do kontakata
	int[] xs1 = { sirina_frejma / 2, sirina_frejma / 2, sirina_frejma / 2 + broj_celija * 100 / 2 + 50,
		sirina_frejma / 2 + broj_celija * 100 / 2 + 50 };
	int[] ys1 = { visina_frejma / 2 - 200 - 30 - 1, visina_frejma / 2 - 200 - 30 - 20,
		visina_frejma / 2 - 200 - 30 - 20, visina_frejma / 2 - 35 };
	g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
	g2.setPaint(Color.black);
	g2.drawPolyline(xs1, ys1, 4);
	int[] xs2 = { sirina_frejma / 2, sirina_frejma / 2, sirina_frejma / 2 + broj_celija * 100 / 2 + 50,
		sirina_frejma / 2 + broj_celija * 100 / 2 + 50 };
	int[] ys2 = { visina_frejma / 2 + 200 + 30 + 1, visina_frejma / 2 + 200 + 30 + 1 + 20,
		visina_frejma / 2 + 200 + 30 + 1 + 20, visina_frejma / 2 + 35 };
	g2.drawPolyline(xs2, ys2, 4);

	// kontakti
	g2.drawOval(xs1[3] - 5, ys1[3], 10, 10);
	g2.drawOval(xs2[3] - 5, ys2[3] - 10, 10, 10);

	g2.drawOval(xs1[3] + 35, visina_frejma / 2 - 5, 10, 10);
	g2.drawLine(xs1[3] + 45, visina_frejma / 2, xs1[3] + 115, visina_frejma / 2);

	g2.draw(new Line2D.Double(tacke_kvadrata[0][0], new Point2D.Double(tacke_kvadrata[0][0].x - 100,
		tacke_kvadrata[0][0].y)));

	g2.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10, new float[] { 7, 6 }, 0));
	g2.drawLine(xs1[3] + 35, visina_frejma / 2 - 2, xs1[3] - 10, ys1[3] + 8);

	Font font = new Font("Courier", Font.TYPE1_FONT, 18);
	g2.setFont(font);
	g2.setColor(Color.black);
	g2.drawString("buffer", (float) tacke_kvadrata[0][0].x + 5, (float) tacke_kvadrata[0][0].y + 5);
    }

    private Point2D.Double[] crtajKvadrat(int x, Graphics2D g2) {
	Rectangle2D.Double e = new Rectangle2D.Double(x, visina_frejma / 2 - 35, 70, 70);
	g2.setPaint(Color.black);
	g2.setStroke(new BasicStroke(8));
	g2.draw(e);
	g2.setPaint(Color.white);
	g2.fill(e);
	Point2D.Double[] results = new Point2D.Double[4];
	results[0] = new Point2D.Double(e.getCenterX() - e.width / 2 - 3, e.getCenterY());
	results[1] = new Point2D.Double(e.getCenterX() + e.width / 2 + 3, e.getCenterY());
	results[2] = new Point2D.Double(e.getCenterX(), e.getCenterY() - e.height / 2 - 3);
	results[3] = new Point2D.Double(e.getCenterX(), e.getCenterY() + e.height / 2 + 3);
	return results;
    }

    private void crtajSabirac(int y, Graphics2D g2) {
	Ellipse2D.Double e = new Ellipse2D.Double(sirina_frejma / 2 - 15, y, 30, 30);
	g2.setPaint(Color.black);
	g2.setStroke(new BasicStroke(8));
	g2.draw(e);
	g2.setPaint(Color.white);
	g2.fill(e);
	g2.setPaint(Color.black);
	g2.setStroke(new BasicStroke(4));
	g2.drawLine(sirina_frejma / 2 - 10, y + 15, sirina_frejma / 2 - 15 + 25, y + 15);
	g2.drawLine(sirina_frejma / 2, y + 5, sirina_frejma / 2, y + 25);
    }
}
